package org.example;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;

/**
 * Copyright (c) 2023-2033 All Rights Reserved
 *
 * Thread、Runnable、ThreadFactory、UncaughtExceptionHandler 异常处理
 * 0. 线程创建
 * 1) 继承 Thread 类，重写 run() 方法
 * 2) 实现 Runnable 接口，重写 run() 方法
 * 3) 实现 Callable 接口，重写 call() 方法，用 FutureTask 封装 Callable 对象，通过构造函数创建线程 Thread(FutureTask, threadName)
 * 4) 线程工厂创建线程
 * 5) 线程池创建线程
 *
 * 1. Runnable 创建需要重写 run() 方法
 *
 * 2. Thread 创建需要重写 run() 方法
 * 1) new Thread()
 * 2) new Thread(Runnable)
 *
 * 3. ThreadFactory
 * 1) Executors.defaultThreadFactory() 创建默认线程工厂
 * 2) new ThreadFactory() 创建自定义线程工厂需要重写 newThread(Runnable r)
 * 3) ThreadFactory.newThread(Runnable r) 创建线程
 * 4) 通过 ThreadFactory 创建线程池后执行
 *
 * 4. 线程异常捕获
 * 1) thread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler)
 * 2) new Thread.UncaughtExceptionHandler 需要重写 uncaughtException(Thread t, Throwable e)
 *
 * @date: 2023/5/6
 */
public class ThreadAndRunnable {
    public static void main(String[] args) throws InterruptedException {
        runnableTest(); // Runnable 创建
        threadTest();   // Thread 创建
        threadFactory(); // ThreadFactory 创建线程
        threadException();  // 线程异常处理
        threadMethod(); // Thread 方法
    }

    // Runnable 创建
    public static void runnableTest() {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                System.out.println("Runnable.run()");
            }
        };

        Runnable runnable1 = () -> {
            System.out.println("Runnable lambda");
        };

        class MyRunnable implements Runnable {
            @Override
            public void run() {
                System.out.println("Class implements Runnable");
            }
        }
    }

    // Thread 创建
    public static void threadTest() {
        // 1. 无参构造函数创建
        Thread thread = new Thread();

        // 2. 构造函数传入任务创建
        Runnable runnable = () -> {
            System.out.println("Thread runnable");
        };
        Thread thread1 = new Thread(runnable);

        Thread thread2 = new Thread(() -> {
            System.out.println("Thread lambda");
        });

        // 3. 线程工厂创建
        Thread thread3 = Executors.defaultThreadFactory().newThread(runnable);

        Thread thread4 = Executors.defaultThreadFactory().newThread(() -> {
                System.out.println("Executors.defaultThreadFactory().newThread()");
            }
        );
        thread4.start();

        new Thread(() -> {}).start();

        // 4. 继承Thread类创建
        class MyThread extends Thread {
            Runnable runnable;

            public MyThread(Runnable runnable) {
                this.runnable = runnable;
            }

            @Override
            public void run() {
                System.out.println("Class extends Thread");
                runnable.run();
            }
        }
        new MyThread(runnable).start();
    }

    // ThreadFactory 创建线程
    public static void threadFactory() {
        Runnable runnable = () -> {
            System.out.println("Thread1 Runnable task");
        };

        // 1. ThreadFactory 通过 Executors 创建默认线程工厂
        ThreadFactory threadFactory = Executors.defaultThreadFactory();
        // 1) ThreadFactory 创建线程
        Thread thread1 = threadFactory.newThread(runnable);
        Thread thread2 = threadFactory.newThread(() -> {
            System.out.println("Thread2 runnable task");
        });
        thread1.start();
        thread2.start();

        // 2) 通过 Executors 创建线程并运行任务
        Executors.defaultThreadFactory().newThread(() -> {
            System.out.println("Thread3 runnable task");
        }).start();

        // 2. 自定义线程工厂
        ThreadFactory threadFactory1 = new ThreadFactory() {
            @Override
            public Thread newThread(Runnable r) {
                Thread thread = new Thread();
                return thread;
            }
        };
        // 1) lambda 表达式
        ThreadFactory threadFactory2 = (r) -> {
            return new Thread(r);
        };

        // 3. 线程工厂通过线程池运行
        ExecutorService executorService2 = Executors.newSingleThreadExecutor(threadFactory2);
        executorService2.execute(() -> {
            System.out.println("ThreadFactory Thread task");
        });
        executorService2.shutdown();
    }

    // 线程异常处理
    public static void threadException() {
        // 定义异常任务
        Runnable runnable = () -> {
            System.out.println("thread execute errRunnable before exception");
            throw new RuntimeException("errRunnable exception");
        };

        // 线程异常处理
        Thread thread = Executors.defaultThreadFactory().newThread(runnable);
        thread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
            @Override
            public void uncaughtException(Thread t, Throwable e) {
                System.out.println("Thread.currentThread().getName() = " + Thread.currentThread().getName());
                System.out.println("t = " + t + ", e = " + e);
                System.out.println("e.getMessage() = " + e.getMessage());
            }
        });
        thread.start();

        // lambda 表达式
        Thread thread1 = Executors.defaultThreadFactory().newThread(() -> {
            System.out.println("thread execute errRunnable before exception");
            throw new RuntimeException("errRunnable exception");
        });
        thread1.setUncaughtExceptionHandler((t, e) -> {
            System.out.println("// Thread.currentThread().getName() = " + Thread.currentThread().getName());
            System.out.println("// t = " + t + ", e = " + e);
            System.out.println("// e.getMessage() = " + e.getMessage());
        });
        thread1.start();
    }

    public static void threadMethod() throws InterruptedException {
        Thread thread = new Thread();
        thread.start();
        thread.isInterrupted();
        thread.interrupt();
        thread.setPriority(5);
        thread.getState();
        thread.getName();
        thread.getThreadGroup();

        thread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
            @Override
            public void uncaughtException(Thread t, Throwable e) {
                System.out.println("t = " + t + " e = " + e);
            }
        });

        Thread.sleep(1000);
        Thread.currentThread();
        Thread.interrupted();
        Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
            @Override
            public void uncaughtException(Thread t, Throwable e) {

            }
        });
    }
}
